﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IsmsExplorer.Model.RiskRegister;
using IsmsExplorer.Infrastructure.Helper;
using IsmsExplorer.Infrastructure.RepositoryFramework;
using IsmsExplorer.Model.AssetRegister;
using System.Diagnostics;
using System.Data;

namespace IsmsExplorer.Infrastructure.Repositories.RiskRegister {
    internal class ThreatRepository : SqlServerRepositoryBase<Threat>, IThreatRepository {
        #region Data
        #endregion

        #region Constructors
        public ThreatRepository(IUnitOfWork unitOfWork) : base(unitOfWork) {
        }

        public ThreatRepository() : this(null) {
        }
        #endregion

        #region IThreatRepository members

        public IList<Threat> FindBy(Asset asset) {            
            // Assertion about Asset ID > 0 commented out as in testing we may try and get non existent Assets
            // (and expect null results of course).
            //Debug.Assert(asset.ID > 0);
            if (asset != null) {
                StringBuilder sb = new StringBuilder(GetBaseQuery());
                sb.AppendFormat(" WHERE {0}={1}", ThreatFactory.FieldNames.AssetID, DataHelper.GetSqlValue(asset.ID)).Append(";");
                return this.BuildEntitiesFromSql(sb.ToString());
            } else {
                return new List<Threat>();
            }
        }

        #endregion

        #region BuildChildDataCallbacks
        protected override void InitialiseChildCallbacks() {
            // NOTE: we do NOT attempt to load the Asset for each Threat as this would lead to infinite loop
            //       as each Asset loads all related Threats!
            //this.ChildCallbacks.Add(ThreatFactory.FieldNames.AssetID, this.AppendAsset);
            // Get the Treatment for this Threat (if one exists).            
        }
        #endregion

        #region Child object callbacks
        //private void AppendAsset(Threat doc, object assetID) {
        //    IAssetRepository r = RepositoryFactory.GetRepository<IAssetRepository, Asset>();
        //    doc.Asset = r.FindByControl(assetID);
        //}
        #endregion        

        #region BuildEntityFromSql override - to get the associated Treatment.

        protected override Threat BuildEntityFromSql(string sql) {
            Threat threat = base.BuildEntityFromSql(sql);
            if (threat != null) {
                // Get the Treatment.
                ITreatmentRepository r = RepositoryFactory.GetRepository<ITreatmentRepository, Treatment>();
                threat.Treatment = r.FindBy(threat);
            }
            return threat;
        }

        #endregion

        #region BuildEntityFromReader override - need it when retrieving a collection of Threats

        protected override Threat BuildEntityFromReader(IDataReader reader) {
            Threat threat = base.BuildEntityFromReader(reader);
            if (threat != null) {
                // Get the Treatment.
                ITreatmentRepository r = RepositoryFactory.GetRepository<ITreatmentRepository, Treatment>();
                threat.Treatment = r.FindBy(threat);
            }
            return threat;
        }

        #endregion

        #region GetBaseQuery
        protected override string GetBaseQuery() {
            return string.Format(@"SELECT {0},{1},{2},{3},{4},{5},{6},{7} FROM [Threats]",
                ThreatFactory.FieldNames.ID,
                ThreatFactory.FieldNames.ProjectID,
                ThreatFactory.FieldNames.AssetID,
                ThreatFactory.FieldNames.Identification,
                ThreatFactory.FieldNames.Description,
                ThreatFactory.FieldNames.Vulnerability,
                ThreatFactory.FieldNames.Likelihood,
                ThreatFactory.FieldNames.Impact);
        }
        #endregion        

        #region GetBaseWhereClause
        protected override string GetBaseWhereClause() {
            StringBuilder sb = new StringBuilder(" WHERE ").Append(ThreatFactory.FieldNames.ID).Append("={0}");
            return sb.ToString();
        }
        #endregion

        #region UnitOfWork implementation
        protected override void PersistDeletedItem(Threat item) {
            string sql = string.Format(@"DELETE FROM [Threats] {0}", this.BuildBaseWhereClause(item.ID));
            this.Database.ExecuteNonQuery(this.Database.GetSqlStringCommand(sql));
        }

        protected override void PersistNewItem(Threat item) {
            StringBuilder sb = new StringBuilder(256);
            sb.AppendFormat(@"INSERT INTO [Threats]({0},{1},{2},{3},{4},{5},{6}) VALUES ({7},{8},{9},{10},{11},{12},{13}); SELECT SCOPE_IDENTITY();",
                ThreatFactory.FieldNames.ProjectID,
                ThreatFactory.FieldNames.AssetID,
                ThreatFactory.FieldNames.Identification,
                ThreatFactory.FieldNames.Description,
                ThreatFactory.FieldNames.Vulnerability,
                ThreatFactory.FieldNames.Likelihood,
                ThreatFactory.FieldNames.Impact,
                DataHelper.GetSqlValue(item.ProjectID),
                DataHelper.GetSqlValue(item.Asset.ID),
                DataHelper.GetSqlValue(item.ThreatIdentification),
                DataHelper.GetSqlValue(item.ThreatDescription),
                DataHelper.GetSqlValue(item.Vulnerability),
                DataHelper.GetSqlValue(item.Likelihood),
                DataHelper.GetSqlValue(item.Impact)
                );
            item.ID = Convert.ToInt32(this.Database.ExecuteScalar(this.Database.GetSqlStringCommand(sb.ToString())));                 
        }

        protected override void PersistUpdatedItem(Threat item) {
            StringBuilder sb = new StringBuilder(@"UPDATE [Threats] SET ");
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.ProjectID, DataHelper.GetSqlValue(item.ProjectID));
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.AssetID, DataHelper.GetSqlValue(item.Asset.ID));
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.Identification, DataHelper.GetSqlValue(item.ThreatIdentification));
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.Description, DataHelper.GetSqlValue(item.ThreatDescription));
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.Vulnerability, DataHelper.GetSqlValue(item.Vulnerability));
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.Likelihood, DataHelper.GetSqlValue(item.Likelihood));
            sb.AppendFormat("{0}={1},", ThreatFactory.FieldNames.Impact, DataHelper.GetSqlValue(item.Impact));
            // Remove the last unnecessary comma character!
            sb.Length -= ",".Length;
            sb.Append(" ").Append(this.BuildBaseWhereClause(item.ID));
            this.Database.ExecuteNonQuery(this.Database.GetSqlStringCommand(sb.ToString()));
        }
        #endregion

        #region Private helper/callback methods
        #endregion

    } // end internal class ThreatRepository : SqlServerRepositoryBase<Asset>, IThreatRepository

}
